package com.sokobanboxpro.game.system;

import com.sokobanboxpro.game.exception.ConfigValueNotFoundException;
import java.io.*;
import org.newdawn.slick.util.LogSystem;

/**
 * Поддерживается логирование в файл и в консоль Уровни логирования: fatal,
 * error, warn, info, trace Настройка способа логирования и уровней логирования
 * производится в конфигурационном файле Пример Logger.info("Hello, World!");
 * @brief Логирования программы
 *
 * @author Esr
 * @version 1.0
 */
public class Logger implements LogSystem {

		/**
		 * @brief Включено ли логировние в файл?
		 */
		private static boolean toFile;
		/**
		 * @brief Включено ли логировние в консоль?
		 */
		private static boolean toConsole;
		/**
		 * @brief Число определяющее включеные уровни логирования
		 */
		private static int mode;
		/**
		 * @brief Булевый массив, определяющий включеные уровни. Каждому номеру
		 * элемента соотвествует порядковый номер уровня
		 */
		private static boolean[] modes;
		/**
		 * @brief Название файла, в которвый будет производиться логирование
		 */
		private static String fileName;
		/**
		 * @brief Указатель на поток в файл
		 */
		private static PrintWriter loggerFile;

		public Logger() throws ConfigValueNotFoundException, FileNotFoundException, UnsupportedEncodingException {

				toFile = Config.toBool("LoggerToFile");
				toConsole = Config.toBool("LoggerToConsole");
				mode = Config.toInt("LoggerMode");
				modes = makeModes(mode);
				if (toFile) {
						fileName = Config.toStr("LoggerFileName");
						loggerFile = openFile();
						fileName = Config.toStr("LoggerFileName");
				}

		}

		/**
		 * @brief Преобразование числа, в массив включеных уровней логирования
		 *
		 * @param mode Число, указывающие на включеные уровни
		 * @return Булевый массив, определяющий включеные уровни. Каждому номеру
		 * элемента соотвествует порядковый номер уровня
		 */
		private boolean[] makeModes(int mode) {


				boolean[] modes = new boolean[6];

				int n = 0, s;

				mode += 16;
				while (mode >= (s = (int) Math.pow(2, n++))) {
						modes[n - 1] = (((mode & s) / s) == 1) ? true : false;
				}

				return modes;

		}

		/**
		 * @brief Открывает файл для чтения
		 *
		 * @return Указатель на поток в файл
		 */
		private PrintWriter openFile() throws FileNotFoundException, UnsupportedEncodingException {
				PrintWriter file = null;

				file = new PrintWriter(new OutputStreamWriter(new FileOutputStream(Logger.fileName), "utf-8"));

				return file;

		}

		/**
		 * @brief Записывает сообщение в файл
		 *
		 * @param message Сообщение, которое надо записать
		 */
		private void writeToFile(String message) {

				loggerFile.write(message + '\n');

		}

		/**
		 * @brief Определяет требуется запись, если да то в куда
		 *
		 * @param message Сообщение, которое надо записать
		 * @param mode Номер уровня логирования
		 */
		private void msg(String message, int mode) {

				if (modes[mode]) {

						String date = (new java.text.SimpleDateFormat("dd-MMM-yy hh:mm:ss aaa")).format(java.util.Calendar.getInstance().getTime());

						message = date + " " + message;

						if (toFile) {
								writeToFile(message);
						}
						if (toConsole) {
								System.out.println(message);
						}

				}

		}

		@Override
		public void error(String string, Throwable thrwbl) {
				msg("Error: " + string + ": " + thrwbl.getMessage(), 3);
		}

		@Override
		public void error(Throwable thrwbl) {
				msg("Error: " + thrwbl.getMessage(), 3);
		}

		@Override
		public void error(String string) {
				msg("Error: " + string, 3);
		}

		@Override
		public void warn(String string) {
				msg("Warn: " + string, 2);
		}

		@Override
		public void warn(String string, Throwable thrwbl) {
				msg("Warn: " + string + ": " + thrwbl.getMessage(), 2);
		}

		@Override
		public void info(String string) {
				msg("Info: " + string, 1);
		}

		@Override
		public void debug(String string) {
				msg("Debug: " + string, 0);
		}

}
